package com.blue.base.common.utils.bean;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.fastjson.JSON;
import com.google.common.collect.Lists;
import org.springframework.beans.BeanUtils;
import org.springframework.util.CollectionUtils;

import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.util.*;

/**
 * @author liulei
 * @version 1.0
 */
public class BeanOptUtil {

    /**
     * 对象拷贝
     */
    public static <T> T copyBean(Object source, Class<T> tClass) {
        try {
            Objects.requireNonNull(source, "拷贝源对象不能为空");
            T newInstance = tClass.newInstance();
            BeanUtil.copyProperties(source, newInstance);
            return newInstance;
        } catch (Exception e) {
            e.printStackTrace();
        }
        throw new IllegalArgumentException("Bean拷贝未知异常");
    }

    /**
     * List集合对象拷贝
     */
    public static <T> List<T> copyList(List<?> list, Class<T> tClass) {
        if (CollectionUtil.isEmpty(list)) {
            return new ArrayList<>();
        }
        return JSON.parseArray(JSON.toJSONString(list), tClass);
    }

    /**
     * Map对象拷贝
     */
    public static Map<String, Object> copyMap(Map<?, ?> map) {
        return JSON.parseObject(JSON.toJSONString(map));
    }

    /**
     * 拷贝实体，source,target不允许为空
     *
     * @param source 源对象
     * @param target 目标对象
     */
    public static void copyProperties(Object source, Object target) {
        BeanUtils.copyProperties(source, target);
    }

    /**
     * 集合拷贝
     *
     * @param sourceList 源对象
     * @param clazz      目标集合的类对象
     */
    public static <T> List<T> copyPropertiesList(List sourceList, Class<T> clazz) {
        if (CollectionUtils.isEmpty(sourceList)) {
            throw new IllegalArgumentException("源对象集合不能为空");
        }
        List targetList = Lists.newArrayListWithExpectedSize(sourceList.size());
        for (Object items : sourceList) {
            Object target = null;
            try {
                target = clazz.newInstance();
            } catch (Exception e) {
                e.printStackTrace();
            }
            BeanUtils.copyProperties(items, target);
            targetList.add(target);
        }
        return targetList;
    }

    /**
     * map->com.blue.base.web.bean
     *
     * @param map map
     * @param obj 目标对象
     */
    public static void transMap2Bean(Map<String, Object> map, Object obj) {
        BeanInfo beanInfo = null;
        try {
            beanInfo = Introspector.getBeanInfo(obj.getClass());
            PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
            for (PropertyDescriptor property : propertyDescriptors) {
                String key = property.getName();
                if (map.containsKey(key)) {
                    Object value = map.get(key);
                    // 得到property对应的setter方法
                    Method setter = property.getWriteMethod();
                    setter.invoke(obj, value);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * Bean --> Map
     *
     * @param obj 源对象
     */
    public static Map<String, Object> transBean2Map(Object obj) {
        Objects.requireNonNull(obj, "源对象不能为空");
        Map<String, Object> map = new HashMap<>(16);
        BeanInfo beanInfo = null;
        try {
            beanInfo = Introspector.getBeanInfo(obj.getClass());
            PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
            for (PropertyDescriptor property : propertyDescriptors) {
                String key = property.getName();
                // 过滤class属性
                if (!key.equals("class")) {
                    // 得到property对应的getter方法
                    Method getter = property.getReadMethod();
                    Object value = getter.invoke(obj);

                    map.put(key, value);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return map;
    }

}
